package yhao.demo.autocode.core.project;

import org.apache.commons.lang3.StringUtils;
import yhao.demo.autocode.core.AutoCodeUtils;
import yhao.infra.common.util.CommonMapUtil;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static yhao.demo.autocode.core.project.NewProjectUtil.*;

public class NewServiceProjectHelper {

    //项目名
    private String projectName;
    //业务线名
    private String bizName;
    //服务名
    private String serviceName;

    private boolean needSolr;
    private boolean needSolr7x;
    private boolean needDubbo;
    private boolean needMysql;
    private boolean needTidb;
    private boolean needH2sql;
    private boolean needOracle;
    private boolean needRedis;
    private boolean needActivemq;
    private boolean needRabbitmq;

    private String serviceDir;
    private String rootServiceDirPath;
    private String rootApiListDirPath;
    private String groupId;
    private String rootPackage;

    /**
     * @param projectName 项目名
     * @param bizName     业务线名
     * @param serviceName 服务模块名
     * @param packagePrefix 包名前缀
     */
    public NewServiceProjectHelper(String projectName, String bizName, String serviceName,String packagePrefix) {
        this.projectName = projectName;
        this.bizName = bizName;
        this.serviceName = serviceName;
        if(StringUtils.isEmpty(projectName) || StringUtils.isEmpty(serviceName) ){
            throw new RuntimeException("projectName或serviceName不得为空");
        }
        groupId = String.format("%s.%sservice",projectName,(StringUtils.isNotEmpty(bizName)?bizName+".":""));
        rootPackage = (StringUtils.isEmpty(packagePrefix)?"":packagePrefix+".")+groupId + "." + serviceName;
        serviceDir = "service" + (StringUtils.isNotEmpty(bizName)?("-"+bizName):"")+"-"+serviceName;
        String rootDir = projectName + (StringUtils.isNotEmpty(bizName)?("-"+bizName):"")+"-"+serviceName;
        String rootDirPath = CONF_DIR_PATH + File.separator + rootDir;
        resetDir(rootDirPath);
        rootServiceDirPath = rootDirPath + File.separator + serviceDir;
        rootApiListDirPath = rootServiceDirPath + "-apilist";
    }

    public void doNew() throws IOException {
        System.out.println(toString());
        System.out.println("开始生成项目文件...");

        System.out.println("开始生成根目录...");
        makeRoot();
        System.out.println("开始生成根目录...DONE");

        System.out.println("开始生成代码文件...");
        makeApiList();
        makeService();
        System.out.println("开始生成代码文件...DONE");

        System.out.println("生成项目文件...DONE");
        System.out.println("完成操作...");
        System.out.println("请到以下地址复制文件..." + CONF_DIR_PATH);
    }

    private void makeApiList() throws IOException {
        makeApiListPomXml();
        makeApiListSrc();
    }
    private void makeService() throws IOException {
        makeServicePomXml();
        makeServiceSrc();
    }

    private void makeApiListSrc() throws IOException {
        String srcPath = rootSrcPath(rootApiListDirPath,"java") + packageToPath(rootPackage) + "apilist";
        new File(srcPath).mkdirs();
        makeApiListForm(srcPath);
        makeApiListModel(srcPath);
        makeApiListRestful(srcPath);

        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage+".apilist");
        String returnCode = AutoCodeUtils.readResource("newProject/newService/apilist/returnCode.new");
        returnCode = AutoCodeUtils.replacePlaceHolder(returnCode,param);
        AutoCodeUtils.makeFile(srcPath,"ReturnCodeEnum.java",returnCode);
    }

    private void makeApiListRestful(String srcPath) throws IOException {
        String path = srcPath + File.separator +"restful";
        new File(path).mkdir();
        String zoneConstants = AutoCodeUtils.readResource("newProject/newService/apilist/zoneConstants.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage+".apilist");
        param.put("serviceDir",serviceDir);
        zoneConstants = AutoCodeUtils.replacePlaceHolder(zoneConstants,param);
        AutoCodeUtils.makeFile(path,"ZoneConstants.java",zoneConstants);

        String firstFeign = AutoCodeUtils.readResource("newProject/newService/apilist/firstFeign.new");
        firstFeign = AutoCodeUtils.replacePlaceHolder(firstFeign,param);
        AutoCodeUtils.makeFile(path,"FirstFeign.java",firstFeign);
    }

    private void makeApiListModel(String srcPath) throws IOException {
        String path = srcPath + File.separator +"model";
        new File(path).mkdir();
        String firstModel = AutoCodeUtils.readResource("newProject/newService/apilist/firstModel.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage+".apilist");
        firstModel = AutoCodeUtils.replacePlaceHolder(firstModel,param);
        AutoCodeUtils.makeFile(path,"FirstModel.java",firstModel);
    }



    private void makeApiListForm(String srcPath) throws IOException {
        String formPath = srcPath + File.separator +"form";
        new File(formPath).mkdir();
        String firstForm = AutoCodeUtils.readResource("newProject/newService/apilist/firstForm.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage+".apilist");
        firstForm = AutoCodeUtils.replacePlaceHolder(firstForm,param);
        AutoCodeUtils.makeFile(formPath,"FirstForm.java",firstForm);
    }

    private void makeApiListPomXml() throws IOException {
        String pom = AutoCodeUtils.readResource("newProject/newService/apilist/pom.new");
        Map<String,String> param = new HashMap<>();
        param.put("artifactId",serviceDir+"-apilist");
        param.put("groupId",groupId);
        param.put("parent-version", AutoCodeUtils.PARENT_VERSION);
        pom = AutoCodeUtils.replacePlaceHolder(pom,param);
        AutoCodeUtils.makeFile(rootApiListDirPath,"pom.xml",pom);
    }

    private void makeConfig(String srcPath) throws IOException {
        String path = srcPath + File.separator +"config";
        new File(path).mkdir();
        String interceptorConfiguration = AutoCodeUtils.readResource("newProject/newService/service/interceptorConfiguration.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        interceptorConfiguration = AutoCodeUtils.replacePlaceHolder(interceptorConfiguration,param);
        AutoCodeUtils.makeFile(path,"InterceptorConfiguration.java",interceptorConfiguration);
    }

    private void makeServiceSrc() throws IOException {
        String srcPath = rootSrcPath(rootServiceDirPath,"java") + packageToPath(rootPackage);
        String resourcePath = rootSrcPath(rootServiceDirPath,"resources");
        new File(srcPath).mkdirs();
        new File(resourcePath).mkdirs();
        makeApi(srcPath);
        makeInterceptor(srcPath);
        makeServiceDir(srcPath);
        makeDao(srcPath);
        makeConfig(srcPath);
        if(needSolr || needSolr7x){
            makeSolr(srcPath);
        }
        if(needDubbo){
            makeDubbo(srcPath);
        }
        if(needActivemq){
            makeActivemq(srcPath);
        }

        String start = AutoCodeUtils.readResource("newProject/newService/service/start.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        StringBuffer importClass = new StringBuffer();
        StringBuffer applicationImport = new StringBuffer();
        String fileName = wordFirstUp(serviceName) +"ServiceApplication";
        param.put("serviceAppName",fileName);
        if(needOracle){
            importClass.append("import yhao.infra.feature.oracle.OracleConfiguration;\n");
            applicationImport.append("OracleConfiguration.class,");
            new File(resourcePath+File.separator+"mybatis"+
                    File.separator+"oracle"+File.separator+serviceName).mkdirs();
        }else if(needMysql){
            importClass.append("import yhao.infra.feature.mysql.MysqlConfiguration;\n");
            applicationImport.append("MysqlConfiguration.class,");
            new File(resourcePath+File.separator+"mybatis"+
                    File.separator+"mysql"+File.separator+serviceName).mkdirs();
        }else if(needTidb){
            importClass.append("import yhao.infra.feature.tidb.TidbConfiguration;\n");
            applicationImport.append("TidbConfiguration.class,");
            new File(resourcePath+File.separator+"mybatis"+
                    File.separator+"tidb"+File.separator+serviceName).mkdirs();
        }else if(needH2sql){
            importClass.append("import yhao.infra.feature.h2sql.H2SqlConfiguration;\n");
            applicationImport.append("H2SqlConfiguration.class,");
            new File(resourcePath+File.separator+"mybatis"+
                    File.separator+"h2sql"+File.separator+serviceName).mkdirs();
        }
        param.put("importClass",importClass.toString());
        param.put("import",applicationImport.toString());
        start = AutoCodeUtils.replacePlaceHolder(start,param);
        AutoCodeUtils.makeFile(srcPath,fileName+".java",start);

        makeApplication(resourcePath);

        makeProperteis(resourcePath);

        makeBootstrap(resourcePath);

        makeLogback(resourcePath);
    }

    private void makeApplication(String resourcePath) throws IOException {
        AutoCodeUtils.makeFile(resourcePath,"application.yml","");
    }

    private void makeActivemq(String srcPath) throws IOException {
        String configPath = srcPath + File.separator +"config";
        new File(configPath).mkdir();
        String activeConfiguration = AutoCodeUtils.readResource("newProject/module/activeConfiguration.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        activeConfiguration = AutoCodeUtils.replacePlaceHolder(activeConfiguration,param);
        AutoCodeUtils.makeFile(configPath,"ActiveConfiguration.java",activeConfiguration);

        String path = srcPath + File.separator +"mq";
        new File(path).mkdir();
        String firstListenerQueue = AutoCodeUtils.readResource("newProject/module/firstListenerQueue.new");
        firstListenerQueue = AutoCodeUtils.replacePlaceHolder(firstListenerQueue,param);
        AutoCodeUtils.makeFile(path,"FirstListenerQueue.java",firstListenerQueue);
    }

    private void makeProperteis(String resourcePath) throws IOException {
        String properties = AutoCodeUtils.readResource("newProject/newService/service/properties.new");
        Map<String,String> param = CommonMapUtil.NEW();
        param.put("activemq-prop",needActivemq? AutoCodeUtils.readResource("newProject/module/props/activemq-prop.new"):"");
        param.put("rabbitmq-prop",needRabbitmq? AutoCodeUtils.readResource("newProject/module/props/rabbitmq-prop.new"):"");
        param.put("dubbo-prop",needDubbo? AutoCodeUtils.readResource("newProject/module/props/dubbo-prop.new"):"");
        param.put("redis-prop",needRedis? AutoCodeUtils.readResource("newProject/module/props/redis-prop.new"):"");
        param.put("solr-prop",(needSolr||needSolr7x)? AutoCodeUtils.readResource("newProject/module/props/solr-prop.new"):"");
        param.put("oracle-prop",needOracle? AutoCodeUtils.readResource("newProject/module/props/oracle-prop.new"):"");
        param.put("mysql-prop",needMysql? AutoCodeUtils.readResource("newProject/module/props/mysql-prop.new"):"");
        param.put("h2sql-prop",needH2sql? AutoCodeUtils.readResource("newProject/module/props/h2sql-prop.new"):"");
        param.put("tidb-prop",needTidb? AutoCodeUtils.readResource("newProject/module/props/tidb-prop.new"):"");
        properties = AutoCodeUtils.replacePlaceHolder(properties,param);
        param.put("serviceName",serviceDir);
        param.put("package",rootPackage);
        param.put("projectName",projectName);
        param.put("hasRedis",needRedis?"":"basic.redis.on=false");
        properties = AutoCodeUtils.replacePlaceHolder(properties,param);
        AutoCodeUtils.makeFile(resourcePath,"application.properties",properties);
    }

    private void makeLogback(String resourcePath) throws IOException {
        String logback = AutoCodeUtils.readResource("newProject/newService/service/logback.new");
        String rootDir = projectName + (StringUtils.isNotEmpty(bizName)?("/"+bizName):"");
        Map<String,String> param = CommonMapUtil.NEW("path",rootDir+"/services/"+serviceDir);
        logback = AutoCodeUtils.replacePlaceHolder(logback,param);
        AutoCodeUtils.makeFile(resourcePath,"logback.xml",logback);
    }

    private void makeBootstrap(String resourcePath) throws IOException {
        Map<String,String> param = CommonMapUtil.NEW("serviceName",serviceDir);
        String bootstrap = AutoCodeUtils.readResource("newProject/module/bootstrap.new");
        bootstrap = AutoCodeUtils.replacePlaceHolder(bootstrap,param);
        AutoCodeUtils.makeFile(resourcePath,"bootstrap.yml",bootstrap);
    }

    private void makeDubbo(String srcPath) throws IOException {
        String configPath = srcPath + File.separator +"config";
        new File(configPath).mkdir();
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        String dubboConfiguration = AutoCodeUtils.readResource("newProject/module/dubboConfiguration.new");
        dubboConfiguration = AutoCodeUtils.replacePlaceHolder(dubboConfiguration,param);
        AutoCodeUtils.makeFile(configPath,"DubboConfiguration.java",dubboConfiguration);
    }

    private void makeSolr(String srcPath) throws IOException {
        String path = srcPath + File.separator +"solr";
        new File(path).mkdir();
        String firstSearcher = AutoCodeUtils.readResource("newProject/newService/service/firstSearcher.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        firstSearcher = AutoCodeUtils.replacePlaceHolder(firstSearcher,param);
        AutoCodeUtils.makeFile(path,"FirstSearcher.java",firstSearcher);

        String configPath = srcPath + File.separator +"config";
        new File(configPath).mkdir();
        String solrConfiguration = AutoCodeUtils.readResource("newProject/newService/service/solrConfiguration.new");
        solrConfiguration = AutoCodeUtils.replacePlaceHolder(solrConfiguration,param);
        AutoCodeUtils.makeFile(configPath,"SolrConfiguration.java",solrConfiguration);
    }

    private void makeDao(String srcPath) throws IOException {
        if(needOracle || needMysql || needH2sql || needTidb){
            String path = srcPath + File.separator +"dao"+File.separator +"automapper";
            new File(path).mkdirs();
            String firstDao = AutoCodeUtils.readResource("newProject/newService/service/firstDao.new");
            Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
            firstDao = AutoCodeUtils.replacePlaceHolder(firstDao,param);
            AutoCodeUtils.makeFile(path,"FirstDao.java",firstDao);

            String configPath = srcPath + File.separator +"config";
            new File(configPath).mkdir();
            String autoMapConfig = AutoCodeUtils.readResource("newProject/newService/service/autoMapConfig.new");
            autoMapConfig = AutoCodeUtils.replacePlaceHolder(autoMapConfig,param);
            AutoCodeUtils.makeFile(configPath,"AutoMapConfig.java",autoMapConfig);
        }
    }

    private void makeServiceDir(String srcPath) throws IOException {
        String path = srcPath + File.separator +"service";
        new File(path).mkdir();
        String firstService = AutoCodeUtils.readResource("newProject/newService/service/firstService.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        firstService = AutoCodeUtils.replacePlaceHolder(firstService,param);
        AutoCodeUtils.makeFile(path,"FirstService.java",firstService);
    }

    private void makeInterceptor(String srcPath) throws IOException {
        String path = srcPath + File.separator +"interceptor";
        new File(path).mkdir();
        String dataSourceKey = serviceDir.toUpperCase().replaceAll("-","_");
        String contextInterceptor = AutoCodeUtils.readResource("newProject/module/contextInterceptor.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        param.put("dataSourceKey",dataSourceKey);
        contextInterceptor = AutoCodeUtils.replacePlaceHolder(contextInterceptor,param);
        AutoCodeUtils.makeFile(path,"ContextInterceptor.java",contextInterceptor);
    }

    private void makeApi(String srcPath) throws IOException {
        String path = srcPath + File.separator +"api";
        new File(path).mkdir();
        String firstApi = AutoCodeUtils.readResource("newProject/newService/service/firstApi.new");
        Map<String,String> param = CommonMapUtil.NEW("rootPackage",rootPackage);
        firstApi = AutoCodeUtils.replacePlaceHolder(firstApi,param);
        AutoCodeUtils.makeFile(path,"FirstApi.java",firstApi);
    }

    private void makeServicePomXml() throws IOException {
        String pom = AutoCodeUtils.readResource("newProject/newService/service/pom.new");
        Map<String,String> param = new HashMap<>();
        param.put("artifactId",serviceDir);
        param.put("groupId",groupId);
        param.put("parent-version", AutoCodeUtils.PARENT_VERSION);
        param.put("redis-pom",needRedis? AutoCodeUtils.readResource("newProject/module/poms/redis-pom.new"):"");
        param.put("dubbo-pom",needDubbo? AutoCodeUtils.readResource("newProject/module/poms/dubbo-pom.new"):"");
        param.put("activemq-pom",needActivemq? AutoCodeUtils.readResource("newProject/module/poms/activemq-pom.new"):"");
        param.put("rabbitmq-pom",needRabbitmq? AutoCodeUtils.readResource("newProject/module/poms/rabbitmq-pom.new"):"");
        param.put("solr-pom",needSolr? AutoCodeUtils.readResource("newProject/module/poms/solr-pom.new"):"");
        param.put("solr7x-pom",needSolr7x? AutoCodeUtils.readResource("newProject/module/poms/solr7x-pom.new"):"");
        param.put("mysql-pom",needMysql? AutoCodeUtils.readResource("newProject/module/poms/mysql-pom.new"):"");
        param.put("oracle-pom",needOracle? AutoCodeUtils.readResource("newProject/module/poms/oracle-pom.new"):"");
        param.put("h2sql-pom",needH2sql? AutoCodeUtils.readResource("newProject/module/poms/h2sql-pom.new"):"");
        param.put("tidb-pom",needTidb? AutoCodeUtils.readResource("newProject/module/poms/tidb-pom.new"):"");
        pom = AutoCodeUtils.replacePlaceHolder(pom,param);
        AutoCodeUtils.makeFile(rootServiceDirPath,"pom.xml",pom);
    }

    private void makeRoot() {
        File root = new File(CONF_DIR_PATH);
        if (!root.exists()) {
            root.mkdir();
        }
        new File(rootServiceDirPath).mkdir();
        new File(rootApiListDirPath).mkdir();
    }

    @Override
    public String toString() {
        return "NewProjectHelper{" +
                "projectName='" + projectName + '\'' +
                ", bizName='" + bizName + '\'' +
                ", serviceName='" + serviceName + '\'' +
                '}';
    }

    public void setNeedSolr(boolean needSolr) {
        this.needSolr = needSolr;
    }

    public void setNeedSolr7x(boolean needSolr7x) {
        this.needSolr7x = needSolr7x;
    }

    public void setNeedDubbo(boolean needDubbo) {
        this.needDubbo = needDubbo;
    }

    public void setNeedMysql(boolean needMysql) {
        this.needMysql = needMysql;
    }

    public void setNeedOracle(boolean needOracle) {
        this.needOracle = needOracle;
    }

    public void setNeedRedis(boolean needRedis) {
        this.needRedis = needRedis;
    }

    public void setNeedActivemq(boolean needActivemq) {
        this.needActivemq = needActivemq;
    }

    public void setNeedH2sql(boolean needH2sql) {
        this.needH2sql = needH2sql;
    }

    public void setNeedTidb(boolean needTidb) {
        this.needTidb = needTidb;
    }

    public void setNeedRabbitmq(boolean needRabbitmq) {
        this.needRabbitmq = needRabbitmq;
    }
}
